package cn.ibdsr.human.aspect;

import cn.ibdsr.human.constant.BizConstants;
import cn.ibdsr.human.exception.BizExceptionEnum;
import cn.ibdsr.human.util.HttpServletUtils;
import cn.ibdsr.human.constant.Result;
import cn.ibdsr.human.exception.BusinessException;
import cn.ibdsr.human.util.ResultUtils;
import com.alibaba.fastjson.JSONObject;
import com.sun.media.sound.InvalidFormatException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.UnexpectedTypeException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 全局的的异常拦截器（拦截所有的控制器，即带有@RequestMapping注解的方法上都会拦截）
 *
 * @author chenglx
 * @version V1.0
 * @date 2021/1/18 10:13
 * <p>
 * Date Author Description
 * ------------------------------------------------------
 * 2021/1/18 chenglx init
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

//
//    /**
//     * 拦截所有异常
//     */
//    @ExceptionHandler(MethodArgumentNotValidException.class)
//    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
//    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
//        HttpServletRequest request = HttpServletUtils.getRequest();
//        HttpServletResponse response = HttpServletUtils.getResponse();
//        log.error("handleException(): 发生未知异常：requestURI: {}, parameterMap: {}", request.getRequestURI(), request.getParameterMap(), e);
//        // 处理失败的情况
//        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
//        // body中返回具体的错误提示
//        String message = e.getBindingResult().getFieldError().getDefaultMessage();
//        return new Result<>(HttpStatus.BAD_REQUEST.value(), message);
//    }

    /**
     * 拦截所有异常
     */
    @ExceptionHandler(UnexpectedTypeException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object handleUnexpectedTypeException(UnexpectedTypeException e) {
        HttpServletRequest request = HttpServletUtils.getRequest();
        HttpServletResponse response = HttpServletUtils.getResponse();
        log.error("handleException(): 发生未知异常：requestURI: {}, parameterMap: {}", request.getRequestURI(), request.getParameterMap(), e);
        // 处理失败的情况
        return new Result<>(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 拦截所有异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object handleException(Exception e) {
        HttpServletRequest request = HttpServletUtils.getRequest();
        HttpServletResponse response = HttpServletUtils.getResponse();
        log.error("handleException(): 发生未知异常：requestURI: {}, parameterMap: {}", request.getRequestURI(), request.getParameterMap(), e);
        // 处理失败的情况
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        // body中返回具体的错误提示
        return new Result<>(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 拦截所有异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public Object handleBusinessException(Exception e) {
        HttpServletRequest request = HttpServletUtils.getRequest();
        HttpServletResponse response = HttpServletUtils.getResponse();
        log.error("handleException(): 发生未知异常：requestURI: {}, parameterMap: {}", request.getRequestURI(), request.getParameterMap(), e);
        // 处理失败的情况
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        // body中返回具体的错误提示
        return new Result<>(HttpStatus.BAD_REQUEST.value(), e.getMessage());//ResultUtils.createErrorMessageBody(e.getMessage());
    }


    /**
     * 拦截参数异常
     */
    @ExceptionHandler({IllegalArgumentException.class, NumberFormatException.class,InvalidFormatException.class})
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object illegalArgumentException(Exception e) {
        log.warn("Catch IllegalArgumentException,   httpStatus: {}, exceptionMsg: {}",
                  HttpStatus.BAD_REQUEST, e.getMessage());
        return new Result<>(HttpStatus.BAD_REQUEST.value(), BizExceptionEnum.REQUEST_PARAM_IS_ERROR.getMessage());
    }

    /**
     * 拦截请求参数校验的异常
     */
    @ExceptionHandler({BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class,
            MissingServletRequestParameterException.class,
            MissingServletRequestPartException.class,
            MultipartException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object paramValidateException(Exception e) {

        log.warn("Catch paramValidateException httpStatus: {}, exceptionMsg: {}",
              HttpStatus.BAD_REQUEST, e.getMessage());
        JSONObject jObjRes = new JSONObject(2);
        // 默认错误提示
        jObjRes.put(BizConstants.ERROR_MSG_KEY, BizExceptionEnum.REQUEST_PARAM_IS_ERROR.getMessage());
        BindingResult bindingResult = null;
        if (e instanceof BindException) {
            BindException subException = (BindException) e;
            bindingResult = subException.getBindingResult();
        } else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException subException = (MethodArgumentNotValidException) e;
            bindingResult = subException.getBindingResult();
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException subException = (ConstraintViolationException) e;
            String message = subException.getConstraintViolations().stream()
                    .map(ConstraintViolation::getMessage).collect(Collectors.joining());
            jObjRes.put(BizConstants.ERROR_MSG_KEY, message);
        }
        if (!Objects.isNull(bindingResult)) {
            // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
            if (bindingResult.hasErrors()) {
                List<ObjectError> errors = bindingResult.getAllErrors();
                if (!errors.isEmpty()) {
                    // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                    FieldError fieldError = (FieldError) errors.get(0);
                    jObjRes.put(BizConstants.ERROR_MSG_KEY, fieldError.getDefaultMessage());
                }
            }
        }
        return new Result<>(HttpStatus.BAD_REQUEST.value(), jObjRes.getString(BizConstants.ERROR_MSG_KEY));
    }
}
